package com.rpoonolly.simplegame.animation;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.rpoonolly.simplegame.Config;
import com.rpoonolly.simplegame.core.Entity;
import com.rpoonolly.simplegame.core.aabb.EntityGameMap;
import com.rpoonolly.simplegame.processors.EntityProcessor;
import com.rpoonolly.simplegame.textures.TextureFileDescriptor;
import com.rpoonolly.simplegame.textures.TextureId;

public abstract class AnimationProcessor<E extends Entity, AnimationType extends Enum<AnimationType>> extends EntityProcessor<E> {
	protected long lastTime;
	protected double dt;
	
	protected long animationStartTime;
	protected AnimationType lastAnimation;
	
	protected TextureFileDescriptor animationMap;
	protected Map<AnimationType, TextureId[]> animations;
	private List<String> groupsToProcess;
	
	protected AnimationProcessor(EntityGameMap<E> gameMap, TextureFileDescriptor animationMap, 
			List<String> groupsToProcess) {
		super(gameMap);
		
		this.animations = new HashMap<AnimationType, TextureId[]>();
		this.groupsToProcess = groupsToProcess;
		this.animationMap = animationMap;
		
		loadAnimationCycles();
	}
	
	@Override
	public void process() {
		List<E> entityList;
		
		processTime();
		for(String groupName : groupsToProcess) {
			entityList = entities.get(groupName);
			for(E entity : entityList)
				processAnimationFrame(entity);
		}
		updateTime();
	}
	
	protected void processTime() {
		if (lastTime == 0) lastTime = System.currentTimeMillis();
		dt = System.currentTimeMillis() - lastTime;
	}
	
	protected void updateTime() {
		lastTime += dt;
	}
	
	protected TextureId getAnimationFrame(AnimationType animationType) {
		if (animationType != lastAnimation) {
			animationStartTime = (long) (lastTime - dt);
			lastAnimation = animationType;
		}
		
		long dt = lastTime - animationStartTime;
		TextureId[] animationCycle = animations.get(animationType);
		
		dt = dt % (animationCycle.length * Config.ANIMATION_FRAME_TIME);
		return animationCycle[(int) (dt / Config.ANIMATION_FRAME_TIME)];
	}
	
	protected abstract void processAnimationFrame(E entity);
	
	protected abstract void loadAnimationCycles();
}
